﻿#pragma once
#include <d3d9.h>
#include <d3dx9.h>
#include <vector>
#include <array>

struct TerrainVertex
{
    D3DXVECTOR3 position;
    D3DXVECTOR3 normal;
    D3DXVECTOR2 texCoord;

    static const DWORD FVF = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_TEX1;
};

class Terrain
{
public:
    Terrain();
    ~Terrain();

    bool Initialize(LPDIRECT3DDEVICE9 device, int width, int height);
    void Render(LPDIRECT3DDEVICE9 device);
    void Cleanup();

    float GetHeight(float x, float z);

private:
    void GenerateHeightMap();
    void CalculateNormals();
    void GenerateTextureCoords();
    bool CreateBuffers(LPDIRECT3DDEVICE9 device);
    bool LoadTextures(LPDIRECT3DDEVICE9 device);
    void BuildLayerIndexData();
    bool CreateLayerIndexBuffers(LPDIRECT3DDEVICE9 device);

    enum TerrainLayer
    {
        LAYER_GRASS = 0,
        LAYER_DIRT,
        LAYER_ROCK,
        LAYER_WATER,
        LAYER_COUNT
    };

    TerrainLayer ClassifyTriangle(int index0, int index1, int index2) const;

    int m_width;
    int m_height;
    int m_vertexCount;
    int m_indexCount;

    std::vector<TerrainVertex> m_vertices;
    std::vector<DWORD> m_indices;
    std::vector<float> m_heightMap;

    LPDIRECT3DVERTEXBUFFER9 m_pVertexBuffer;
    LPDIRECT3DINDEXBUFFER9 m_pIndexBuffer;

    std::array<std::vector<DWORD>, LAYER_COUNT> m_layerIndices;
    std::array<LPDIRECT3DINDEXBUFFER9, LAYER_COUNT> m_layerIndexBuffers;
    std::array<int, LAYER_COUNT> m_layerIndexCounts;

    LPDIRECT3DTEXTURE9 m_pTextureGrass;
    LPDIRECT3DTEXTURE9 m_pTextureDirt;
    LPDIRECT3DTEXTURE9 m_pTextureRock;
    LPDIRECT3DTEXTURE9 m_pTextureWater;
};
